﻿using System;
using System.Threading;

namespace Sunny.FrameDecoder
{
    /// <summary>
    /// 值类型计数定时器(默认计数周期1秒，计数时间间隔需小于计数周期)
    /// </summary>
    public struct ValueCountTimer
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="period">计数周期</param>
        public ValueCountTimer(TimeSpan period)
        {
            Period = period;
        }

        /// <summary>
        /// 构造函数，默认计数周期1秒
        /// </summary>
        public ValueCountTimer()
        {
            Period = TimeSpan.FromSeconds(1);
        }

        /// <summary>
        /// 周期内的累计计数值。
        /// </summary>
        private long _count;

        /// <summary>
        /// 最后一次递增时间
        /// </summary>
        private DateTime _lastAdded;

        /// <summary>
        /// 周期内的累计计数值。
        /// </summary>
        public long Count => _count;

        /// <summary>
        /// 最后一次递增时间
        /// </summary>
        public DateTime LastAdded => _lastAdded;

        /// <summary>
        /// 当达到一个周期时触发。
        /// </summary>
        public Action<long> Tick { get; set; }

        /// <summary>
        /// 计数周期，。
        /// </summary>
        public TimeSpan Period { get; set; }

        /// <summary>
        /// 累计增加计数
        /// </summary>
        /// <param name="value"></param>
        /// <returns>返回值表示当前递增的是否在一个周期内。</returns>
        public bool Add(long value = 1)
        {
            bool isPeriod;
            if (DateTime.Now - this.LastAdded > this.Period)
            {
                this.Tick?.Invoke(this._count);
                Interlocked.Exchange(ref this._count, 0);
                isPeriod = false;
                this._lastAdded = DateTime.Now;
            }
            else
            {
                isPeriod = true;
            }

            Interlocked.Add(ref this._count, value);
            return isPeriod;
        }

        /// <summary>
        /// 重置
        /// </summary>
        public void Reset()
        {
            this._count = 0;
            this._lastAdded = default;
        }
    }
}
